package iscte.ai.kcgtd;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

import android.app.Activity;
import android.os.Bundle;
import android.provider.SyncStateContract.Constants;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.RelativeLayout;

public class Suggestion extends Activity {

	private static final int BUFFER_SIZE = 6;
	private static final int SCHEDULE_HOURS= 10;
	
	private ArrayList<Task> goals;
	private ArrayList<FreeBlocks> todayCalendar;
	private ArrayList<FreeBlocks> tomorrowCalendar;
	private ArrayList<FreeBlocks> todayElementsToRemove;
	private ArrayList<FreeBlocks> tomorrowElementsToRemove;
	private Task[] buffer;
	protected static int suggestionsAccepted;
	private Thread updateButton;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.list);
		
		goals = new ArrayList<Task>();
		todayCalendar = new ArrayList<FreeBlocks>();
		tomorrowCalendar = new ArrayList<FreeBlocks>();
		todayElementsToRemove = new ArrayList<FreeBlocks>();
		tomorrowElementsToRemove = new ArrayList<FreeBlocks>();
		
		goals.addAll(MainActivity.projectos);
		goals.addAll(MainActivity.lazer);
		goals.addAll(MainActivity.compras);
		
		if(goals.size() > BUFFER_SIZE)
			buffer = new Task[BUFFER_SIZE];
		else
			buffer = new Task[goals.size()];
		
		//ORDENAR LISTA DE OBJECTIVOS POR PRIORIDADE
		
		for (int i = 0; i < buffer.length; i++){
			if(i < goals.size())
				buffer[i] = goals.get(i);
			else
				continue;
		}
		
		//CALENDARIZAR
		KCGTDTime today = new KCGTDTime();
		todayCalendar = ProviderCalendar.getFreeCalendarSpaces(this, today);
		
		KCGTDTime tomorrow = getTomorrowDate();
		tomorrowCalendar = ProviderCalendar.getFreeCalendarSpaces(this, tomorrow);
		
		ArrayList<PeriodStats> bestPeriods;
		
		for (int i = 0; i < buffer.length; i++) {
			Task t = buffer[i];
			bestPeriods = Statistics.getBestTime(t.getCategoria());
			
			for (PeriodStats periodStats : bestPeriods) {
				if(schedule(t, periodStats)){
					break;
				}
			}
			
			if(!todayElementsToRemove.isEmpty())
				todayCalendar.removeAll(todayElementsToRemove);
			
			if(!tomorrowElementsToRemove.isEmpty())
				tomorrowCalendar.removeAll(tomorrowElementsToRemove);
			
		}
		
		ListView list = (ListView) findViewById(R.id.list);
		buffer = removeUnscheduledTasks(buffer);
		Arrays.sort(buffer);
		CheckListAdapter adapter = new CheckListAdapter(this, buffer);
		list.setAdapter(adapter);
		
		
		RelativeLayout relative = new RelativeLayout(this); 
		RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

		final Button confirm = new Button(this);
		confirm.setText("Confirm");
		confirm.setEnabled(false);
		
		updateButton = new Thread(new Runnable() {
			boolean stopThread = false;
			
            public void run() {
            	try {
            		while(!stopThread) {
            			if(suggestionsAccepted >= buffer.length){
            				stopThread = true;
            				Suggestion.this.runOnUiThread(new Runnable() {	
								@Override
								public void run() {
									confirm.setEnabled(true);
								}
							});
            			}
            			Thread.sleep(1000);
                    }
                } catch (Exception e) {
                	Log.d(Constants.DATA, "Thread terminada!");
                }
            }
        });
        updateButton.start();
		
		confirm.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				for (Task t : buffer) {
					if(t.isScheduled()){
						ProviderCalendar.addTaskToCalendar(getApplicationContext(), t);
						//Atribuir pontuação à slot escolhida
						t.getPeriodStatsUsed().incrementPoints(t.getCategoria());
						
						removeFromList(MainActivity.projectos, t);
						removeFromList(MainActivity.lazer, t);
						removeFromList(MainActivity.compras, t);
					}else{
						t.getPeriodStatsUsed().decrementPoints(t.getCategoria());
						t.setTimeStart(null);
						t.setTimeEnd(null);
						t.setPeriodStatsUsed(null);
					}
				}
				
				suggestionsAccepted = 0;
				
				//Reagendar uma nova calendarização
				Utils.createScheduledNotification(Suggestion.this, true, SCHEDULE_HOURS);
				
				//Gravar alterações nas listas
				Bag bag = new Bag();
				bag.fillBag();
				Utils.saveData(Suggestion.this, bag);
				
				Suggestion.this.finish();
			}

			private void removeFromList(ArrayList<Task> list, Task task) {
				if(list.contains(task))
					list.remove(task);
			}
		});
		
		relative.addView(confirm, params);

		addContentView(relative, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
	}

	private Task[] removeUnscheduledTasks(Task[] buffer) {
		ArrayList<Task> result = new ArrayList<Task> ();
		for (Task task : buffer) {
			if(task.getTimeStart()!=null)
				result.add(task);
		}
		return result.toArray(new Task[result.size()]);
	}

	private boolean schedule(Task task , PeriodStats periodStats) {
		
		for (FreeBlocks freeBlock : todayCalendar) {
			if(blockSchedule(task, periodStats, freeBlock, true)){
				return true;
			}
		}
		
		for (FreeBlocks freeBlock : tomorrowCalendar) {
			boolean success = blockSchedule(task, periodStats, freeBlock, false);
			if(success)
				return true;
		}

		return false;	
		
	}

	private boolean blockSchedule(Task task, PeriodStats periodStats, FreeBlocks freeBlock, boolean today) {
		if (freeBlock.getStartTime().getHour() >= periodStats.getHora_inicio() && freeBlock.getStartTime().getHour() < periodStats.getHora_fim()){
			
			if (timeFitsBlock(task.getDuration(), freeBlock.getDuration())){
				task.setTimeStart(freeBlock.getStartTime());
				
				KCGTDTime end = new KCGTDTime(0, freeBlock.getStartTime().getMinute() + task.getDuration().getMinute(), (freeBlock.getStartTime().getHour() + task.getDuration().getHour()), freeBlock.getEndTime().getMonthDay(), freeBlock.getEndTime().getMonth(), freeBlock.getEndTime().getYear());
				end.normalize(true);
				task.setTimeEnd(end);
				task.setPeriodStatsUsed(periodStats);
				
				freeBlock.setStartTime(task.getTimeEnd());
				
				freeBlock.updateDuration();
				
				if(freeBlock.getStartTime().equals(freeBlock.getEndTime())){
					if(today)
						todayElementsToRemove.add(freeBlock);
					else
						tomorrowElementsToRemove.add(freeBlock);
				}
				 return true;
			}
			
		}else if(freeBlock.getEndTime().getHour() > periodStats.getHora_inicio() && freeBlock.getEndTime().getHour() < periodStats.getHora_fim()){
			
			KCGTDTime t = new KCGTDTime(freeBlock.getStartTime());
			t.setHour(periodStats.getHora_inicio());
			
			FreeBlocks newFreeBlock = new FreeBlocks(t, freeBlock.getEndTime(), null);
			
			if (timeFitsBlock(task.getDuration(), newFreeBlock.getDuration())){
				task.setTimeStart(newFreeBlock.getStartTime());
				
				KCGTDTime end = new KCGTDTime(newFreeBlock.getStartTime());
				end.setHour(newFreeBlock.getStartTime().getHour() + task.getDuration().getHour());
				end.setMinute(newFreeBlock.getStartTime().getMinute() + task.getDuration().getMinute());
				end.normalize(true);
				task.setTimeEnd(end);
				task.setPeriodStatsUsed(periodStats);
				
				freeBlock.setEndTime(task.getTimeStart());
				newFreeBlock.setStartTime(task.getTimeEnd());
				
				OccupiedBlocks newOccupiedBlocks = new OccupiedBlocks(task.getTimeStart(), task.getTimeEnd(), task.getName(), task.getLocation());
				newFreeBlock.setPreviousBlock(newOccupiedBlocks);
				
				freeBlock.updateDuration();
				newFreeBlock.updateDuration();
				
				if(!newFreeBlock.getStartTime().equals(newFreeBlock.getEndTime())){
					if(today)
						todayCalendar.add(newFreeBlock);
					else
						tomorrowCalendar.add(newFreeBlock);
				}
				 return true;
			}
			
		}else if(periodStats.getHora_inicio() > freeBlock.getStartTime().getHour() && periodStats.getHora_fim() <= freeBlock.getEndTime().getHour()){
			
			KCGTDTime pStatsStart;
			
			if(today == true){
				pStatsStart = new KCGTDTime();
				pStatsStart.setHour(periodStats.getHora_inicio());
				pStatsStart.setMinute(0);
				pStatsStart.setSecond(0);
			}else{
				pStatsStart = getTomorrowDate();
				pStatsStart.setHour(periodStats.getHora_inicio());
				pStatsStart.setMinute(0);
				pStatsStart.setSecond(0);
			}
			
			KCGTDTime aux = Utils.getDurationBetweenHours(pStatsStart, freeBlock.getEndTime());
			
			if (timeFitsBlock(task.getDuration(), aux)){
				task.setTimeStart(pStatsStart);
				
				KCGTDTime end = new KCGTDTime(freeBlock.getStartTime());
				end.setHour(task.getTimeStart().getHour() + task.getDuration().getHour());
				end.setMinute(task.getTimeStart().getMinute() + task.getDuration().getMinute());
				end.normalize(true);
				task.setTimeEnd(end);
				task.setPeriodStatsUsed(periodStats);
				
				if(!freeBlock.getEndTime().equals(task.getTimeEnd())){
					OccupiedBlocks newOccupiedBlocks = new OccupiedBlocks(task.getTimeStart(), task.getTimeEnd(), task.getName(), task.getLocation());
					FreeBlocks newFreeBlock = new FreeBlocks(task.getTimeEnd(), freeBlock.getEndTime(), newOccupiedBlocks);
					
					if(today)
						todayCalendar.add(newFreeBlock);
					else
						tomorrowCalendar.add(newFreeBlock);
				}
				
				freeBlock.setEndTime(task.getTimeStart());
				
				freeBlock.updateDuration();
				
				return true;
			}
			
		}
		
		return false;
	}

	private boolean timeFitsBlock(KCGTDTime taskDuration, KCGTDTime blockDuration) {
		if(blockDuration.getHour() - taskDuration.getHour() == 0){
			if(blockDuration.getMinute() - taskDuration.getMinute() >= 0){
				return true;
			}else{
				return false;
			}
		}else if(blockDuration.getHour() - taskDuration.getHour() > 0){
			return true;
		}else{
			return false;
		}
	}

	private KCGTDTime getTomorrowDate() {
		Date d = new Date();
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.DATE, 1);
		
		KCGTDTime newTime = new KCGTDTime(c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.MONTH), c.get(Calendar.YEAR));
		return newTime;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.suggestion, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

}
